package com.xh.core.util;

import com.zhuozhengsoft.base64.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * RSA加解密工具
 *
 * @author: 赵文博
 * @date: 2021/4/7
 */
public class RSAUtils {

    private static final String ALGORITHM = "RSA";
    private static final String CHARSET = "utf-8";

    /**
     * 生成密钥对
     *
     * @return java.util.Map<java.lang.String, java.lang.String>
     * @author 赵文博
     * @date 2021/4/7 11:31
     **/
    public static Map<String, String> createKey() {
        Map<String, String> map = new HashMap();
        KeyPairGenerator kpg = null;
        try {
            kpg = KeyPairGenerator.getInstance(ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        kpg.initialize(1024);//初始化密钥对大小，密钥长度
        KeyPair keyPair = kpg.generateKeyPair();//生成密钥对
        Key privateKey = keyPair.getPrivate();//私钥
        Key publicKey = keyPair.getPublic();//公钥
        map.put("privateKey", Base64.encodeBase64URLSafeString(privateKey.getEncoded()));
        map.put("publicKey", Base64.encodeBase64URLSafeString(publicKey.getEncoded()));
        return map;
    }

    /**
     * 获取公钥对象 X509编码
     *
     * @param publicKeyStr
     * @return java.security.interfaces.RSAPublicKey
     * @author 赵文博
     * @date 2021/4/7 11:37
     **/
    private static RSAPublicKey getPublicKey(String publicKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException {
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyStr));
        RSAPublicKey rsaPublicKey = (RSAPublicKey) keyFactory.generatePublic(x509EncodedKeySpec);
        return rsaPublicKey;
    }

    /**
     * 获取私钥对象 PKCS#8编码
     *
     * @param privateKeyStr
     * @return java.security.interfaces.RSAPrivateKey
     * @author 赵文博
     * @date 2021/4/7 11:49
     **/
    private static RSAPrivateKey getPrivateKey(String privateKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException {
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyStr));
        RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        return rsaPrivateKey;
    }

    /**
     * 公钥加密
     *
     * @param publicKeyStr
     * @return java.lang.String
     * @author 赵文博
     * @date 2021/4/7 11:53
     **/
    public static String encryptByPublicKey(String publicKeyStr, String data) {
        String encryptFile = "";
        try {
            RSAPublicKey rsaPublicKey = getPublicKey(publicKeyStr);
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, rsaPublicKey);
            encryptFile = Base64.encodeBase64String(cipher.doFinal(data.getBytes(CHARSET)));
            return encryptFile;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        }
        return encryptFile;
    }

    /**
     * 私钥加密
     *
     * @param privateKeyStr
     * @param data
     * @return void
     * @author 赵文博
     * @date 2021/4/7 14:04
     **/
    public static String encryptByPrivateKey(String privateKeyStr, String data) {
        String encryptFile = "";
        try {
            RSAPrivateKey rsaPrivateKey = getPrivateKey(privateKeyStr);
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, rsaPrivateKey);
            encryptFile = Base64.encodeBase64String(cipher.doFinal(data.getBytes(CHARSET)));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return encryptFile;
    }

    /**
     * 私钥解密
     *
     * @param privateKeyStr
     * @param data
     * @return void
     * @author 赵文博
     * @date 2021/4/7 13:53
     **/
    public static String decryptByPrivateKey(String privateKeyStr, String data) {
        String decrypt = "";
        try {
            byte[] input = Base64.decodeBase64(data.getBytes(CHARSET));
            RSAPrivateKey rsaPrivateKey = getPrivateKey(privateKeyStr);
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(cipher.DECRYPT_MODE, rsaPrivateKey);
            decrypt = new String(cipher.doFinal(input));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        return decrypt;
    }

    /**
     * 公钥解密
     *
     * @param publicKeyStr
     * @param data
     * @return void
     * @author 赵文博
     * @date 2021/4/7 14:08
     **/
    public static String decryptByPublicKey(String publicKeyStr, String data) {
        String decrypt = "";
        try {
            byte[] input = Base64.decodeBase64(data.getBytes(CHARSET));
            RSAPublicKey rsaPublicKey = getPublicKey(publicKeyStr);
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(cipher.DECRYPT_MODE, rsaPublicKey);
            decrypt = new String(cipher.doFinal(input));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        }
        return decrypt;
    }

    public static void main(String[] args) {
        String date = "999";
        Path path = Paths.get("D://RSA//privateKey.txt");
        try {
            byte[] data = Files.readAllBytes(path);
            String encryptDate = encryptByPrivateKey(new String(data, CHARSET),date);
            FileWriter fileWriter3 = new FileWriter("D://RSA//expireDate.txt");
            fileWriter3.write(encryptDate);
            fileWriter3.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}
